#include "../include/CPlayerBehaviour.h"
#include "../include/CDefaultShotBehaviour.h"
#include "../include/CBombShotBehaviour.h"
#include "../include/CSpriteAnimation.h"

#include <SDL/SDL.h>

#define STRAIGHT_SHOT_SPEED 15
#define MIDDLE_SHOT_SPEED 10
#define SIDE_SHOT_SPEED 7

//**************************
//Description : Constructor
//Parameters : Value for m_iX, m_iY,
//              m_iSpeedX, m_iSpeedY,
//              m_iWidth, m_iHeight,
//              the ratio for the collision box
//              the type of colision
//              and m_iLives
//Note : None
//**************************
CPlayerBehaviour::CPlayerBehaviour(int _iX, int _iY,
                                    int _iSpeedX, int _iSpeedY,
                                    int _iWidth, int _iHeight,
                                    float _fRatioW, float _fRatioH,
                                    TYPE_COLLISION _iTypeCollision,
                                    int _iLives)
    : IMovableEntityBehaviour(_iX, _iY,
                                _iSpeedX, _iSpeedY,
                                _iWidth, _iHeight,
                                _fRatioW, _fRatioW,
                                _iTypeCollision,
                                _iLives),
    m_lCurrentScore(0),
    m_iEnemiesKilled(0)
{
    m_iPrimaryShot = DEFAULTSHOT;
    m_iSecondaryShot = BOMB;

    m_iTimeBetweenPrimaryShot = 100;
    m_iTimeBetweenSecondaryShot = 800;

    m_iNBShots = new int[2]();

    for (int i = 0; i < 2; i++)
        m_iNBShots[i] = 1;

    for (int i = 0; i < MAX_SHOTS; i++)
        m_DirectionShots[i] = new Rect[i+1]();

    //1 shot
    m_DirectionShots[0][0].iX = 0;
    m_DirectionShots[0][0].iY = 0;
    m_DirectionShots[0][0].iSpeedX = 0;
    m_DirectionShots[0][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    //2shots
    m_DirectionShots[1][0].iX = -10;
    m_DirectionShots[1][0].iY = 0;
    m_DirectionShots[1][0].iSpeedX = 0;
    m_DirectionShots[1][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[1][1].iX = 10;
    m_DirectionShots[1][1].iY = 0;
    m_DirectionShots[1][1].iSpeedX = 0;
    m_DirectionShots[1][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    //3 shots
    m_DirectionShots[2][0].iX = 0;
    m_DirectionShots[2][0].iY = 0;
    m_DirectionShots[2][0].iSpeedX = -SIDE_SHOT_SPEED;
    m_DirectionShots[2][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[2][1].iX = 0;
    m_DirectionShots[2][1].iY = 0;
    m_DirectionShots[2][1].iSpeedX = 0;
    m_DirectionShots[2][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[2][2].iX = 0;
    m_DirectionShots[2][2].iY = 0;
    m_DirectionShots[2][2].iSpeedX = SIDE_SHOT_SPEED;
    m_DirectionShots[2][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    //4 shots
    m_DirectionShots[3][0].iX = 0;
    m_DirectionShots[3][0].iY = 0;
    m_DirectionShots[3][0].iSpeedX = -MIDDLE_SHOT_SPEED;
    m_DirectionShots[3][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[3][1].iX = 0;
    m_DirectionShots[3][1].iY = 0;
    m_DirectionShots[3][1].iSpeedX = 0;
    m_DirectionShots[3][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[3][2].iX = 0;
    m_DirectionShots[3][2].iY = 0;
    m_DirectionShots[3][2].iSpeedX = MIDDLE_SHOT_SPEED;
    m_DirectionShots[3][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[3][3].iX = 0;
    m_DirectionShots[3][3].iY = 0;
    m_DirectionShots[3][3].iSpeedX = 0;
    m_DirectionShots[3][3].iSpeedY = STRAIGHT_SHOT_SPEED;

    //5 shots
    m_DirectionShots[4][0].iX = 0;
    m_DirectionShots[4][0].iY = 0;
    m_DirectionShots[4][0].iSpeedX = -STRAIGHT_SHOT_SPEED;
    m_DirectionShots[4][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[4][1].iX = 0;
    m_DirectionShots[4][1].iY = 0;
    m_DirectionShots[4][1].iSpeedX = 0;
    m_DirectionShots[4][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[4][2].iX = 0;
    m_DirectionShots[4][2].iY = 0;
    m_DirectionShots[4][2].iSpeedX = STRAIGHT_SHOT_SPEED;
    m_DirectionShots[4][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[4][3].iX = 0;
    m_DirectionShots[4][3].iY = 0;
    m_DirectionShots[4][3].iSpeedX = -SIDE_SHOT_SPEED;
    m_DirectionShots[4][3].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[4][4].iX = 0;
    m_DirectionShots[4][4].iY = 0;
    m_DirectionShots[4][4].iSpeedX = SIDE_SHOT_SPEED;
    m_DirectionShots[4][4].iSpeedY = STRAIGHT_SHOT_SPEED;

    //6 shots
    m_DirectionShots[5][0].iX = -10;
    m_DirectionShots[5][0].iY = 0;
    m_DirectionShots[5][0].iSpeedX = -STRAIGHT_SHOT_SPEED;
    m_DirectionShots[5][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[5][1].iX = -10;
    m_DirectionShots[5][1].iY = 0;
    m_DirectionShots[5][1].iSpeedX = 0;
    m_DirectionShots[5][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[5][2].iX = 10;
    m_DirectionShots[5][2].iY = 0;
    m_DirectionShots[5][2].iSpeedX = 0;
    m_DirectionShots[5][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[5][3].iX = 10;
    m_DirectionShots[5][3].iY = 0;
    m_DirectionShots[5][3].iSpeedX = STRAIGHT_SHOT_SPEED;
    m_DirectionShots[5][3].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[5][4].iX = 0;
    m_DirectionShots[5][4].iY = 0;
    m_DirectionShots[5][4].iSpeedX = -SIDE_SHOT_SPEED;
    m_DirectionShots[5][4].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[5][5].iX = 0;
    m_DirectionShots[5][5].iY = 0;
    m_DirectionShots[5][5].iSpeedX = SIDE_SHOT_SPEED;
    m_DirectionShots[5][5].iSpeedY = STRAIGHT_SHOT_SPEED;

    //7 shots
    m_DirectionShots[6][0].iX = -10;
    m_DirectionShots[6][0].iY = 0;
    m_DirectionShots[6][0].iSpeedX = -STRAIGHT_SHOT_SPEED;
    m_DirectionShots[6][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][1].iX = -10;
    m_DirectionShots[6][1].iY = 0;
    m_DirectionShots[6][1].iSpeedX = 0;
    m_DirectionShots[6][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][2].iX = 10;
    m_DirectionShots[6][2].iY = 0;
    m_DirectionShots[6][2].iSpeedX = 0;
    m_DirectionShots[6][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][3].iX = 10;
    m_DirectionShots[6][3].iY = 0;
    m_DirectionShots[6][3].iSpeedX = STRAIGHT_SHOT_SPEED;
    m_DirectionShots[6][3].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][4].iX = 0;
    m_DirectionShots[6][4].iY = 0;
    m_DirectionShots[6][4].iSpeedX = -MIDDLE_SHOT_SPEED;
    m_DirectionShots[6][4].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][5].iX = 0;
    m_DirectionShots[6][5].iY = 0;
    m_DirectionShots[6][5].iSpeedX = 0;
    m_DirectionShots[6][5].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[6][6].iX = 0;
    m_DirectionShots[6][6].iY = 0;
    m_DirectionShots[6][6].iSpeedX = MIDDLE_SHOT_SPEED;
    m_DirectionShots[6][6].iSpeedY = STRAIGHT_SHOT_SPEED;

    //8 shots
    m_DirectionShots[7][0].iX = 0;
    m_DirectionShots[7][0].iY = 0;
    m_DirectionShots[7][0].iSpeedX = -STRAIGHT_SHOT_SPEED;
    m_DirectionShots[7][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][1].iX = 0;
    m_DirectionShots[7][1].iY = 0;
    m_DirectionShots[7][1].iSpeedX = -SIDE_SHOT_SPEED;
    m_DirectionShots[7][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][2].iX = 0;
    m_DirectionShots[7][2].iY = 0;
    m_DirectionShots[7][2].iSpeedX = 0;
    m_DirectionShots[7][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][3].iX = 0;
    m_DirectionShots[7][3].iY = 0;
    m_DirectionShots[7][3].iSpeedX = SIDE_SHOT_SPEED;
    m_DirectionShots[7][3].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][4].iX = 0;
    m_DirectionShots[7][4].iY = 0;
    m_DirectionShots[7][4].iSpeedX = STRAIGHT_SHOT_SPEED;
    m_DirectionShots[7][4].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][5].iX = 0;
    m_DirectionShots[7][5].iY = 0;
    m_DirectionShots[7][5].iSpeedX = -MIDDLE_SHOT_SPEED;
    m_DirectionShots[7][5].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][6].iX = 0;
    m_DirectionShots[7][6].iY = 0;
    m_DirectionShots[7][6].iSpeedX = 0;
    m_DirectionShots[7][6].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[7][7].iX = 0;
    m_DirectionShots[7][7].iY = 0;
    m_DirectionShots[7][7].iSpeedX = MIDDLE_SHOT_SPEED;
    m_DirectionShots[7][7].iSpeedY = STRAIGHT_SHOT_SPEED;

    //9 shots
    m_DirectionShots[8][0].iX = -10;
    m_DirectionShots[8][0].iY = 0;
    m_DirectionShots[8][0].iSpeedX = -STRAIGHT_SHOT_SPEED;
    m_DirectionShots[8][0].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][1].iX = -10;
    m_DirectionShots[8][1].iY = 0;
    m_DirectionShots[8][1].iSpeedX = -SIDE_SHOT_SPEED;
    m_DirectionShots[8][1].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][2].iX = -10;
    m_DirectionShots[8][2].iY = 0;
    m_DirectionShots[8][2].iSpeedX = 0;
    m_DirectionShots[8][2].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][3].iX = 10;
    m_DirectionShots[8][3].iY = 0;
    m_DirectionShots[8][3].iSpeedX = 0;
    m_DirectionShots[8][3].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][4].iX = 10;
    m_DirectionShots[8][4].iY = 0;
    m_DirectionShots[8][4].iSpeedX = SIDE_SHOT_SPEED;
    m_DirectionShots[8][4].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][5].iX = 1;
    m_DirectionShots[8][5].iY = 0;
    m_DirectionShots[8][5].iSpeedX = STRAIGHT_SHOT_SPEED;
    m_DirectionShots[8][5].iSpeedY = -STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][6].iX = 0;
    m_DirectionShots[8][6].iY = 0;
    m_DirectionShots[8][6].iSpeedX = -MIDDLE_SHOT_SPEED;
    m_DirectionShots[8][6].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][7].iX = 0;
    m_DirectionShots[8][7].iY = 0;
    m_DirectionShots[8][7].iSpeedX = 0;
    m_DirectionShots[8][7].iSpeedY = STRAIGHT_SHOT_SPEED;

    m_DirectionShots[8][8].iX = 0;
    m_DirectionShots[8][8].iY = 0;
    m_DirectionShots[8][8].iSpeedX = MIDDLE_SHOT_SPEED;
    m_DirectionShots[8][8].iSpeedY = STRAIGHT_SHOT_SPEED;
}

//**************************
//Description : Copy Constructor
//Parameters : A CPlayerBehaviour
//Note : None
//**************************
CPlayerBehaviour::CPlayerBehaviour(CPlayerBehaviour & _Player)
    : IMovableEntityBehaviour(_Player),
    m_lCurrentScore(_Player.m_lCurrentScore),
    m_iEnemiesKilled(_Player.m_iEnemiesKilled)
{
    m_iNBShots = new int[2]();

    for (int i = 0; i < 2; i++)
        m_iNBShots[i] = _Player.m_iNBShots[i];

    for (int i = 0; i < MAX_SHOTS; i++)
    {
        m_DirectionShots[i] = new Rect[i+1]();

        for (int j = 0; j <= i; j++)
        {
            m_DirectionShots[i][j].iSpeedX = _Player.m_DirectionShots[i][j].iSpeedX;
            m_DirectionShots[i][j].iSpeedY = _Player.m_DirectionShots[i][j].iSpeedY;
            m_DirectionShots[i][j].iX = _Player.m_DirectionShots[i][j].iX;
            m_DirectionShots[i][j].iY = _Player.m_DirectionShots[i][j].iY;
        }
    }
}

//**************************
//Description : Destructor
//Parameters : None
//Note : None
//**************************
CPlayerBehaviour::~CPlayerBehaviour()
{
    if ( m_iNBShots != NULL )
        delete[] m_iNBShots;

    for (int i = 0; i < MAX_SHOTS; i++)
    {
        if ( m_DirectionShots[i] != NULL )
            delete[] m_DirectionShots[i];
    }
}

//**************************
//Description : The player can throw 2 more shots at a time
//Parameters : The type of shot that is powered up
//Return Value : None
//Note : None
//**************************
void CPlayerBehaviour::ShotsUp(int _iTypeOfShot)
{
    if ( _iTypeOfShot >= 0 && _iTypeOfShot < 2 )
    {
        if ( m_iNBShots[_iTypeOfShot] + 1 <= MAX_SHOTS )
            m_iNBShots[_iTypeOfShot]++;
    }
}

//**************************
//Description : Add _iNbPoints to the score of the player
//Parameters : The number of points to add
//Return Value : None
//Note : None
//**************************
void CPlayerBehaviour::AddPoints(long _iNbPoints)
{
    m_lCurrentScore += _iNbPoints;

    if (m_lCurrentScore < 0)
        m_lCurrentScore = 0;
}

//**************************
//Description : Return the score of the player
//Parameters : None
//Return Value : The score of the player
//Note : None
//**************************
long CPlayerBehaviour::GetPoints() const
{
    return m_lCurrentScore;
}

//**************************
//Description : Set the number of shots for each shots
//Parameters : The tab of the number of shots
//Return Value : None
//Note : None
//**************************
void CPlayerBehaviour::SetNbShots(int * _iNbShots)
{
    for (int i = 0; i < 2; i++)
    {
        if ( m_iNBShots == NULL )
            m_iNBShots = new int[2]();

        m_iNBShots[i] = _iNbShots[i];
    }
}

//**************************
//Description : Return the number of shots of each type of shot
//Parameters : None
//Return Value : The tab of nb shots
//Note : None
//**************************
int * CPlayerBehaviour::GetNbShots() const
{
    return m_iNBShots;
}

//**************************
//Description : Add an enemy to the number of killed enemy
//Parameters : The number of ennemies
//Return Value : None
//Note : None
//**************************
void CPlayerBehaviour::AddEnemiesKilled(int _iNbEnemiesKilled)
{
    m_iEnemiesKilled += _iNbEnemiesKilled;
}

//**************************
//Description : Return the number of enemies that the player killed
//Parameters : None
//Return Value : The number of enemies that the player killed
//Note : None
//**************************
int CPlayerBehaviour::GetEnemiesKilled() const
{
    return m_iEnemiesKilled;
}

//**************************
//Description : The entity shoot
//Parameters : The tab of animations shot and the screen
//Return Value : True if the enemy has shot, otherwise false
//Note : Virtual because the way of shooting depends on the entity
//**************************
bool CPlayerBehaviour::Shoot(CSpriteAnimation * _SpriteAnimationShot, SDL_Surface * _screen)
{
    //we get the state of the key board
    Uint8* keys;

    keys = SDL_GetKeyState(NULL);

    //we test the keys in order to know what shot create
    if ( keys[SDLK_SPACE] && ( (Uint32)(m_lLastPrimaryShoot + m_iTimeBetweenPrimaryShot) < SDL_GetTicks() ) )
    {
        CDefaultShotBehaviour * Shot;

        switch ( m_iPrimaryShot )
        {
            case DEFAULTSHOT:
            {
                for (int i = 0; i < m_iNBShots[0]; i++)
                {
                    Shot = new CDefaultShotBehaviour(m_iX+m_DirectionShots[m_iNBShots[0]-1][i].iX,
                                                    m_iY+m_DirectionShots[m_iNBShots[0]-1][i].iY,
                                                    m_DirectionShots[m_iNBShots[0]-1][i].iSpeedX,
                                                    m_DirectionShots[m_iNBShots[0]-1][i].iSpeedY,
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                    Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                    m_vShots->push_back( Shot );
                }

                break;
            }
            case BOMB:
            {
                for (int i = 0; i < m_iNBShots[0]; i++)
                {
                    Shot = new CBombShotBehaviour(m_iX+m_DirectionShots[m_iNBShots[0]-1][i].iX,
                                                    m_iY+m_DirectionShots[m_iNBShots[0]-1][i].iY,
                                                    m_DirectionShots[m_iNBShots[0]-1][i].iSpeedX,
                                                    m_DirectionShots[m_iNBShots[0]-1][i].iSpeedY,
                                                    _SpriteAnimationShot[BOMB].GetWidth(),
                                                    _SpriteAnimationShot[BOMB].GetHeight());

                    Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                    m_vShots->push_back( Shot );
                }

                break;
            }
            default:
            {
                Shot = new CDefaultShotBehaviour(m_iX, m_iY,
                                                    0, -2,
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );
            }
        }

        m_lLastPrimaryShoot = SDL_GetTicks();

        return true;
    }

    if ( keys[SDLK_b] && ( (Uint32)(m_lLastSecondaryShoot + m_iTimeBetweenSecondaryShot) < SDL_GetTicks() ) )
    {
        CDefaultShotBehaviour * Shot;

        switch ( m_iSecondaryShot )
        {
            case DEFAULTSHOT:
            {
                for (int i = 0; i < m_iNBShots[1]; i++)
                {
                    Shot = new CDefaultShotBehaviour(m_iX+m_DirectionShots[m_iNBShots[1]-1][i].iX,
                                                    m_iY+m_DirectionShots[m_iNBShots[1]-1][i].iY,
                                                    m_DirectionShots[m_iNBShots[1]-1][i].iSpeedX,
                                                    m_DirectionShots[m_iNBShots[1]-1][i].iSpeedY,
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                    Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                    m_vShots->push_back( Shot );
                }

                break;
            }
            case BOMB:
            {
                for (int i = 0; i < m_iNBShots[1]; i++)
                {
                    Shot = new CBombShotBehaviour(m_iX+m_DirectionShots[m_iNBShots[1]-1][i].iX,
                                                    m_iY+m_DirectionShots[m_iNBShots[1]-1][i].iY,
                                                    m_DirectionShots[m_iNBShots[1]-1][i].iSpeedX,
                                                    m_DirectionShots[m_iNBShots[1]-1][i].iSpeedY,
                                                    _SpriteAnimationShot[BOMB].GetWidth(),
                                                    _SpriteAnimationShot[BOMB].GetHeight());

                    Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                    m_vShots->push_back( Shot );
                }

                break;
            }
            default:
            {
                Shot = new CBombShotBehaviour(m_iX, m_iY,
                                                0, -2,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

				break;
            }
        }

        m_lLastSecondaryShoot = SDL_GetTicks();

        return true;
    }

    return false;
}

//**************************
//Description : Update the trajectory of the entity
//Parameters : None
//Return Value : None
//Note : Virtual because actions depends on the entity type
//**************************
void CPlayerBehaviour::EntityTrajectory()
{
    Uint8* keys;

    keys = SDL_GetKeyState(NULL);

    if ( keys[SDLK_UP] )
    {
        m_iY -= m_iSpeedY;

        if ( !IsInTheScreen() )
            m_iY += m_iSpeedY;
    }

    if ( keys[SDLK_DOWN] )
    {
        m_iY += m_iSpeedY;

        if ( !IsInTheScreen() )
            m_iY -= m_iSpeedY;
    }

    if ( keys[SDLK_LEFT] )
    {
        m_iX -= m_iSpeedX;

        if ( !IsInTheScreen() )
            m_iX += m_iSpeedX;
    }

    if ( keys[SDLK_RIGHT] )
    {
        m_iX += m_iSpeedX;

        if ( !IsInTheScreen() )
            m_iX -= m_iSpeedX;
    }
}
